package com.haier.npt.filter.authorization;

import java.io.IOException;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.Route;

import com.haier.npt.authention.support.PermissionSupport;
import com.haier.npt.common.JsonResult;
import com.haier.npt.exception.BizBaseException;
import com.haier.npt.exception.ExceptionCode;
import com.haier.npt.filter.AbstractProcessingFilter;
import com.haier.npt.security.client.SysPermisssionClient;
import com.haier.npt.security.domain.SysPermission;
import com.haier.npt.security.dto.RequestInfoDTO;
import com.haier.npt.sso.resources.SysAppCacheResource;


/**
 * @Description:权限过滤器
 * @author: lixu
 * @date:   2018年7月12日 下午5:23:30   
 */
public abstract class AbstractAuthorizationFilter extends AbstractProcessingFilter {
	
	
	@Autowired
	protected PermissionSupport permissionSupport;	
	
	
	@Autowired
	protected SysPermisssionClient sysPermisssionClient ; 
	
	/**
	 * 取token 和 sysapp 对应的token 关系
	 */
	@Autowired
	protected SysAppCacheResource sysAppCacheResource;

	@Autowired
	private AuthProviderManager authProviderManager;
	
	/**
	 * 匹配服务名的正则表达式
	 */
	protected String serviceIdPattern =  "(?<name>^.+)-(?<version>v.+$)" ; 
	
	private static final Logger logger = LoggerFactory.getLogger(AbstractAuthorizationFilter.class);

	@Override
	public Object run() {
		try {
			Route route = routeLocator.getMatchingRoute(super.getCtx().getRequest().getRequestURI());
			if (!authProviderManager.doAuthorization(super.getCtx().getRequest(), super.getCtx().getResponse(), route)) {
				this.onAuthFailure(super.getCtx());
			}
		} catch (BizBaseException ex){
			super.processBizZuulException(ex);
		}catch (Exception ex) {
			super.processZuulException(ex);
		}
		return null;
	}

	/**
	 * 如果ignore为true ， 则不执行此过滤器 ,没有登录失败标识也执行该过滤器
	 */
	@Override
	public boolean shouldFilter() {
		return !getCtx().getBoolean("ignore") &&  !getCtx().getBoolean("loginFaulure");
	}
	
	
	/**
	 * 校验权限
	 * @param request
	 * @param response
	 * @param mappedValue
	 * @return
	 * @throws IOException
	 */
	protected boolean doAuthorization(HttpServletRequest request, HttpServletResponse response) {
		Set<String> permissionCodeSet = this.getPermissionCode(request);
		// 不为空说明需要验证权限
		if (permissionCodeSet != null && !permissionCodeSet.isEmpty()) {
			// 得到当前用户的权限
			List<SysPermission> permissions = this.onAuthorization(request, response);
			// 校验权限
			return this.isAccessAllowed(permissions, permissionCodeSet);
		}
		return true;
	}
	
	/**
	 * 判断当前登录人有哪些权限
	 * @param request
	 * @param response
	 * @return
	 */
	abstract List<SysPermission>  onAuthorization(HttpServletRequest request ,HttpServletResponse response) ;
	
	/**
	 * 检验授权
	 * @param userPermissions 当前用户的权限
	 * @param urlPermissions url 需要的权限
	 * @return
	 */
	protected  boolean isAccessAllowed(List<SysPermission> userPermissions , Set<String> urlPermissions){
		if (urlPermissions == null || urlPermissions.isEmpty()) {
			return true;
		}
		for (int x = 0; x < userPermissions.size(); x++) {
			SysPermission sysPermission = userPermissions.get(x);
			if (urlPermissions.contains(sysPermission.getPermissionCode()) && sysPermission.isAvailable()) {
				return true;
			}
		}
		return false;
	}
	/**
	 * 返回url 需要的权限信息 ,返回null 说明不需要权限
	 * @return
	 */
	protected Set<String> getPermissionCode(HttpServletRequest request){
		
		RequestInfoDTO requestInfoDTO = new RequestInfoDTO() ; 
		
		// 根据url 分析此url 需要的权限信息
		Route route = routeLocator.getMatchingRoute(request.getRequestURI());
		if (route!=null) {
			String serviceId =  route.getLocation() ; //获取服务的id
			if(serviceId.matches(serviceIdPattern)){
				serviceId = StringUtils.substringBeforeLast(serviceId, "-"); 
			}
			//设置服务名
			requestInfoDTO.setServiceId(serviceId);
			requestInfoDTO.setMethod(request.getMethod());
			requestInfoDTO.setUrl(route.getPath());
			
			JsonResult<Set<String>> jsonResult = sysPermisssionClient.getPermissionCode(requestInfoDTO);
			if(jsonResult.getCode()==0 && jsonResult.getData()!=null){
				return jsonResult.getData() ; 
			}else{
				logger.error("根据url获取权限code失败，【 服务名: {} , 方法：{} ， 访问路径:{} 】"  , serviceId,request.getMethod(),route.getPath());
				new BizBaseException(ExceptionCode.SYSTEM_ERROR); //系统异常
			}
		}
		return null ; 
	}
}
